home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / vdremote / Main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-05  |  23.1 KB  |  904 lines

  1. #include <crtdbg.h>
  2. #include <objbase.h>
  3.  
  4. #include "clsid.h"
  5. #include "vdremote.h"
  6. #include "vdserver.h"
  7.  
  8. #pragma warning(disable: 4355)        // warning C4355: 'this' : used in base member initializer list
  9.  
  10. long CAVIFileRemote::gRefCnt = 0;
  11. long CAVIStreamRemote::gRefCnt = 0;
  12.  
  13. ////////////////////////////////////////////////////////////
  14.  
  15. const GUID CDECL CLSID_AVIFile
  16.     = { 0x00020000, 0, 0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  17.  
  18. const GUID CDECL another_IID_IAVIFile
  19.     = { 0x00020020, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  20.  
  21. const GUID CDECL another_IID_IAVIStream
  22.     = { 0x00020021, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  23.  
  24. const GUID CDECL CLSID_Avisynth
  25.     = { 0xE6D6B700, 0x124D, 0x11D4, 0x86, 0xF3, 0xDB, 0x80, 0xAF, 0xD9, 0x87, 0x78};
  26.  
  27. ////////////////////////////////////////////////////////////
  28.  
  29. BOOL APIENTRY DllMain(HANDLE hModule, ULONG ulReason, LPVOID lpReserved) {
  30.  
  31.     switch(ulReason) {
  32.     case DLL_PROCESS_ATTACH:
  33.         CoInitialize(NULL);
  34.         _RPT0(0,"Process attach\n");
  35.         break;
  36.  
  37.     case DLL_PROCESS_DETACH:
  38.         CoUninitialize();
  39.         _RPT0(0,"Process detach\n");
  40.         break;
  41.     }
  42.  
  43.     return TRUE;
  44. }
  45.  
  46. const GUID CDECL CLSID_CAVIFileRemote
  47.     = {0x894288e0,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  48. const GUID CDECL CLSID_CAVIStreamRemote
  49.     = {0x91379540,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  50.  
  51. // From the Microsoft AVIFile docs.  Dense code...
  52.  
  53. extern "C" STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv);
  54.  
  55. STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv) {
  56.     HRESULT hresult;
  57.  
  58.     _RPT0(0,"DllGetClassObject()\n");
  59.  
  60.     if (rclsid == CLSID_CAVIStreamRemote) {
  61.         _RPT0(0,"\tCLSID: CAVIStreamRemote\n");
  62.         hresult = CAVIStreamRemote::Create(rclsid, riid, ppv);
  63.     } else { // if (rclsid == CLSID_CAVIStreamRemote) {
  64.         _RPT0(0,"\tCLSID: CAVIFileRemote (default) \n");
  65.         hresult = CAVIFileRemote::Create(rclsid, riid, ppv);
  66.     }
  67.  
  68.     _RPT0(0,"DllGetClassObject() exit\n");
  69.  
  70.     return hresult;
  71. }
  72.  
  73. extern "C" STDAPI DllCanUnloadNow();
  74.  
  75. STDAPI DllCanUnloadNow() {
  76.     _RPT2(0,"DllCanUnloadNow(): CAVIFileRemote %ld, CAVIStreamRemote %ld\n", CAVIFileRemote::gRefCnt, CAVIStreamRemote::gRefCnt);
  77.  
  78.     return (CAVIFileRemote::gRefCnt || CAVIStreamRemote::gRefCnt) ? S_FALSE : S_OK;
  79. }
  80.  
  81.  
  82. ///////////////////////////////////////////////////////////////////////////
  83. //
  84. //    CAVIFileRemote
  85. //
  86. ///////////////////////////////////////////////////////////////////////////
  87.  
  88.  
  89. HRESULT CAVIFileRemote::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  90.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  91.  
  92.     return Create(CLSID_CAVIFileRemote, riid, ppvObj);
  93. }
  94.  
  95. HRESULT CAVIFileRemote::LockServer (BOOL fLock) {
  96.     _RPT1(0,"%p->CAVIFileRemote::LockServer()\n", this);
  97.     return S_OK;
  98. }
  99.  
  100. STDMETHODIMP CAVIFileRemote::GetClassID(LPCLSID lpClassID) {
  101.     _RPT1(0,"%p->CAVIFileRemote::GetClassID()\n", this);
  102.  
  103.     *lpClassID = CLSID_CAVIFileRemote;
  104.  
  105.     return S_OK;
  106. }
  107.  
  108. STDMETHODIMP CAVIFileRemote::IsDirty() {
  109.     _RPT1(0,"%p->CAVIFileRemote::IsDirty()\n", this);
  110.     return S_FALSE;
  111. }
  112.  
  113. STDMETHODIMP CAVIFileRemote::Load(LPCOLESTR lpszFileName, DWORD grfMode) {
  114.     char filename[MAX_PATH];
  115.  
  116.     _RPT1(0,"%p->CAVIFileRemote::Load()\n", this);
  117.  
  118.     WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, lpszFileName, -1, filename, sizeof filename, NULL, NULL); 
  119.  
  120.     return Open(filename, grfMode, lpszFileName);
  121. }
  122.  
  123. STDMETHODIMP CAVIFileRemote::Save(LPCOLESTR lpszFileName, BOOL fRemember) {
  124.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  125.     return E_FAIL;
  126. }
  127.  
  128. STDMETHODIMP CAVIFileRemote::SaveCompleted(LPCOLESTR lpszFileName) {
  129.     _RPT1(0,"%p->CAVIFileRemote::SaveCompleted()\n", this);
  130.     return S_OK;
  131. }
  132.  
  133. STDMETHODIMP CAVIFileRemote::GetCurFile(LPOLESTR *lplpszFileName) {
  134.     _RPT1(0,"%p->CAVIFileRemote::GetCurFile()\n", this);
  135.     *lplpszFileName = NULL;
  136.  
  137.     return E_FAIL;
  138. }
  139.  
  140. ///////////////////////////////////////////////////
  141.  
  142. HRESULT CAVIFileRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  143.     CAVIFileRemote *pAVIFileRemote;
  144.     HRESULT hresult;
  145.  
  146.     _RPT0(0,"CAVIFileRemote::Create()\n");
  147.  
  148.     pAVIFileRemote = new CAVIFileRemote(rclsid);
  149.  
  150.     if (!pAVIFileRemote) return ResultFromScode(E_OUTOFMEMORY);
  151.  
  152.     hresult = pAVIFileRemote->QueryInterface(riid, ppv);
  153.     pAVIFileRemote->Release();
  154.     if (FAILED(GetScode(hresult))) {
  155.         _RPT0(0,"failed!\n");
  156.     }
  157.  
  158.     _RPT0(0,"CAVIFileRemote::Create() exit\n");
  159.  
  160.     return hresult;
  161. }
  162.  
  163. STDMETHODIMP CAVIFileRemote::QueryInterface(const IID& iid, void **ppv) {
  164.     _RPT1(0,"%08lx->CAVIFileRemote::QueryInterface()\n", this);
  165.  
  166.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  167.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  168.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  169.  
  170.     if (iid == IID_IUnknown) {
  171.         *ppv = (IUnknown *)(IAVIFile *)this;
  172.         _RPT0(0,"IUnknown)\n");
  173.     } else if (iid == IID_IClassFactory) {
  174.         *ppv = (IClassFactory *)this;
  175.         _RPT0(0,"IClassFactory)\n");
  176.     } else if (iid == IID_IPersist) {
  177.         *ppv = (IPersist *)this;
  178.         _RPT0(0,"IPersist)\n");
  179.     } else if (iid == IID_IPersistFile) {
  180.         *ppv = (IPersistFile *)this;
  181.         _RPT0(0,"IPersistFile)\n");
  182.     } else if (iid == another_IID_IAVIFile) {
  183.         *ppv = (IAVIFile *)this;
  184.         _RPT0(0,"IAVIFile)\n");
  185.     } else {
  186.         _RPT0(0,"unknown!)\n");
  187.         *ppv = NULL;
  188.         return ResultFromScode(E_NOINTERFACE);
  189.     }
  190.  
  191.     AddRef();
  192.  
  193.     return NULL;
  194. }
  195.  
  196. STDMETHODIMP_(ULONG) CAVIFileRemote::AddRef() {
  197.     _RPT1(0,"%p->CAVIFileRemote::AddRef()\n", this);
  198.     ++gRefCnt;
  199.     return ++m_refs;
  200. }
  201.  
  202. STDMETHODIMP_(ULONG) CAVIFileRemote::Release() {
  203.     _RPT1(0,"%p->CAVIFileRemote::Release()\n", this);
  204.  
  205.     if (!--m_refs)
  206.         delete this;
  207.  
  208.     --gRefCnt;
  209.  
  210.     _RPT0(0,"CAVIFileRemote::Release() exit\n");
  211.  
  212.     return m_refs;
  213. }
  214.  
  215. ///////////////////////////////////////////////////////////////////////////
  216. //
  217. //    CAVIStreamRemote - binding glue
  218. //
  219. ///////////////////////////////////////////////////////////////////////////
  220.  
  221. CAVIStreamClassFactory::CAVIStreamClassFactory(CAVIStreamRemote *af) {
  222.     avifile = af;
  223. }
  224.  
  225. HRESULT CAVIStreamClassFactory::QueryInterface (REFIID riid, void * * ppvObj) {
  226.     return avifile->QueryInterface(riid, ppvObj);
  227. }
  228.  
  229. unsigned long  CAVIStreamClassFactory::AddRef () {
  230.     return avifile->AddRef();
  231. }
  232.  
  233. unsigned long  CAVIStreamClassFactory::Release () {
  234.     return avifile->Release();
  235. }
  236.  
  237. HRESULT CAVIStreamClassFactory::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  238.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  239.  
  240.     return avifile->Create(CLSID_CAVIFileRemote, riid, ppvObj);
  241. }
  242.  
  243. HRESULT CAVIStreamClassFactory::LockServer (BOOL fLock) {
  244.     return S_OK;
  245. }
  246.  
  247. ///////////////////////
  248.  
  249. HRESULT CAVIStreamRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  250.     CAVIStreamRemote *pAVIStreamRemote;
  251.     IUnknown *pUnknown;
  252.     HRESULT hresult;
  253.  
  254.     _RPT0(0,"CAVIStreamRemote::Create()\n");
  255.  
  256.     pAVIStreamRemote = new CAVIStreamRemote(rclsid, (void **)&pUnknown);
  257.  
  258.     if (!pAVIStreamRemote) return ResultFromScode(E_OUTOFMEMORY);
  259.  
  260.     hresult = pUnknown->QueryInterface(riid, ppv);
  261.     pAVIStreamRemote->Release();
  262.     if (FAILED(GetScode(hresult)))
  263.         _RPT0(0,"Failed!\n");
  264.  
  265.     _RPT0(0,"CAVIStreamRemote::Create() exit\n");
  266.  
  267.     return hresult;
  268. }
  269.  
  270. STDMETHODIMP CAVIStreamRemote::QueryInterface(const IID& iid, void **ppv) {
  271.     _RPT1(0,"%08lx->CAVIStreamRemote::QueryInterface()\n", this);
  272.  
  273.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  274.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  275.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  276.  
  277.     if (iid == IID_IUnknown) {
  278.         *ppv = (IUnknown *)this;
  279.         _RPT0(0,"IUnknown)\n");
  280.     } else if (iid == IID_IClassFactory) {
  281.         *ppv = (IClassFactory *)&iclassfactory;
  282.         _RPT0(0,"IClassFactory)\n");
  283.     } else if (iid == IID_IAVIStream) {
  284.         *ppv = (IAVIStream *)this;
  285.         _RPT0(0,"IAVIStream)\n");
  286.     } else {
  287.         _RPT0(0,"unknown)\n");
  288.         *ppv = NULL;
  289.         return ResultFromScode(E_NOINTERFACE);
  290.     }
  291.  
  292.     AddRef();
  293.  
  294.     return NULL;
  295. }
  296.  
  297. STDMETHODIMP_(ULONG) CAVIStreamRemote::AddRef() {
  298.     _RPT0(0,"CAVIStreamRemote::AddRef()\n");
  299.  
  300.     ++gRefCnt;
  301.     return ++m_refs;
  302. }
  303.  
  304. STDMETHODIMP_(ULONG) CAVIStreamRemote::Release() {
  305.     _RPT0(0,"CAVIStreamRemote::Release()\n");
  306.  
  307.     if (!--m_refs)
  308.         delete this;
  309.  
  310.     --gRefCnt;
  311.  
  312.     _RPT0(0,"CAVIStreamRemote::Release() exit\n");
  313.  
  314.     return m_refs;
  315. }
  316.  
  317. ////////////////////////////////////////////////////////////////////////
  318. //
  319. //        CAVIFileRemote
  320. //
  321. ////////////////////////////////////////////////////////////////////////
  322.  
  323. STDMETHODIMP CAVIFileRemote::CreateStream(PAVISTREAM *ppStream, AVISTREAMINFOW *psi) {
  324.     _RPT1(0,"%p->CAVIFileRemote::CreateStream()\n", this);
  325.  
  326.     if (pafTunnel)
  327.         return pafTunnel->CreateStream(ppStream, psi);
  328.  
  329.     return AVIERR_READONLY;
  330. }
  331.  
  332. STDMETHODIMP CAVIFileRemote::EndRecord() {
  333.     _RPT1(0,"%p->CAVIFileRemote::EndRecord()\n", this);
  334.  
  335.     if (pafTunnel)
  336.         return pafTunnel->EndRecord();
  337.  
  338.     return AVIERR_READONLY;
  339. }
  340.  
  341. STDMETHODIMP CAVIFileRemote::Save(LPCSTR szFile, AVICOMPRESSOPTIONS FAR *lpOptions,
  342.                 AVISAVECALLBACK lpfnCallback) {
  343.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  344.  
  345.     return AVIERR_READONLY;
  346. }
  347.  
  348. STDMETHODIMP CAVIFileRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  349.     _RPT1(0,"%p->CAVIFileRemote::ReadData()\n", this);
  350.  
  351.     if (pafTunnel)
  352.         return pafTunnel->ReadData(fcc, lp, lpcb);
  353.  
  354.     return AVIERR_NODATA;
  355. }
  356.  
  357. STDMETHODIMP CAVIFileRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  358.     _RPT1(0,"%p->CAVIFileRemote::WriteData()\n", this);
  359.  
  360.     if (pafTunnel)
  361.         return pafTunnel->WriteData(fcc, lpBuffer, cbBuffer);
  362.  
  363.     return AVIERR_READONLY;
  364. }
  365.  
  366. STDMETHODIMP CAVIFileRemote::DeleteStream(DWORD fccType, LONG lParam) {
  367.     _RPT1(0,"%p->CAVIFileRemote::DeleteStream()\n", this);
  368.  
  369.     if (pafTunnel)
  370.         return pafTunnel->DeleteStream(fccType, lParam);
  371.  
  372.     return AVIERR_READONLY;
  373. }
  374.  
  375.  
  376.  
  377.  
  378. CAVIFileRemote::CAVIFileRemote(const CLSID& rclsid) {
  379.     _RPT0(0,"CAVIFileRemote::CAVIFileRemote()\n");
  380.  
  381.     m_refs = 0; AddRef();
  382.  
  383.     szPath = NULL;
  384.     ivdsl = NULL;
  385.     ivdac = NULL;
  386.     vFormat = NULL;
  387.     aFormat = NULL;
  388.     pafTunnel = NULL;
  389.  
  390.     InitializeCriticalSection(&csPort);
  391. }
  392.  
  393. CAVIFileRemote::~CAVIFileRemote() {
  394.     _RPT0(0,"CAVIFileRemote::~CAVIFileRemote()\n");
  395.  
  396.     DeleteCriticalSection(&csPort);
  397.  
  398.     if (ivdac) ivdsl->FrameServerDisconnect(ivdac);
  399.     delete szPath;
  400.  
  401.     if (pafTunnel)
  402.         pafTunnel->Release();
  403. }
  404.  
  405.  
  406. STDMETHODIMP CAVIFileRemote::Open(LPCSTR szFile, UINT mode, LPCOLESTR lpszFileName) {
  407.     HMMIO hmmio = NULL;
  408.     MMCKINFO mmiriff, mmi;
  409.     MMRESULT mmerr;
  410.     HRESULT final = S_OK;
  411.  
  412.     _RPT2(0,"CAVIFileRemote::Open(\"%s\", %08lx)\n", szFile, mode);
  413.  
  414.     if (pafTunnel) {
  415.         pafTunnel->Release();
  416.         pafTunnel = NULL;
  417.     }
  418.  
  419.     if (mode & (OF_CREATE|OF_WRITE)) {
  420.         IPersistFile *ppf;
  421.  
  422.         if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  423.             return (HRESULT)E_FAIL;
  424.  
  425.         if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  426.             return (HRESULT)E_FAIL;
  427.  
  428.         HRESULT hr = ppf->Load(lpszFileName, mode);
  429.  
  430.         ppf->Release();
  431.  
  432.         return hr;
  433.     }
  434.  
  435.     if (!(hmmio = mmioOpen((char *)szFile, NULL, MMIO_READ)))
  436.         return E_FAIL;
  437.  
  438.     _RPT0(0,"File opened.\n");
  439.  
  440.     // RIFF <size> VDRM { PATH <remote-path> }
  441.  
  442.     try {
  443.         char buf[16];
  444.  
  445.         _RPT0(0,"Checking for Avisynth signature...\n");
  446.  
  447.         if (16==mmioRead(hmmio, buf, 16)) {
  448.             buf[9] = 0;
  449.             if (!_stricmp(buf, "#avisynth")) {
  450.  
  451.                 mmioClose(hmmio, 0);
  452.  
  453.                 // Hand it off to the Avisynth handler.
  454.  
  455.                 IPersistFile *ppf;
  456.  
  457.                 // Okay, it's not one of our files.  Now try passing it off
  458.                 // to the regular AVI handler!
  459.  
  460.                 _RPT0(0,"Attempt avisynth tunnel create\n");
  461.  
  462.                 if (FAILED(CoCreateInstance(CLSID_Avisynth, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  463.                     return (HRESULT)E_FAIL;
  464.  
  465.                 _RPT0(0,"Attempt avisynth tunnel query -> IPersistFile\n");
  466.  
  467.                 if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  468.                     return (HRESULT)E_FAIL;
  469.  
  470.                 _RPT0(0,"Attempt avisynth tunnel load\n");
  471.  
  472.                 HRESULT hr = ppf->Load(lpszFileName, mode);
  473.  
  474.                 ppf->Release();
  475.  
  476.                 return hr;
  477.             }
  478.         }
  479.  
  480.         mmioSeek(hmmio, 0, SEEK_SET);
  481.  
  482.         _RPT0(0,"Attempting to find 'VDRM'...\n");
  483.  
  484.         mmiriff.fccType = 'MRDV';
  485.         mmerr = mmioDescend(hmmio, &mmiriff, NULL, MMIO_FINDRIFF);
  486.         if (mmerr == MMIOERR_CHUNKNOTFOUND) {
  487.             IPersistFile *ppf;
  488.  
  489.             mmioClose(hmmio, 0);
  490.  
  491.             // Okay, it's not one of our files.  Now try passing it off
  492.             // to the regular AVI handler!
  493.  
  494.             _RPT0(0,"Attempt tunnel create\n");
  495.  
  496.             if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  497.                 return (HRESULT)E_FAIL;
  498.  
  499.             _RPT0(0,"Attempt tunnel query -> IPersistFile\n");
  500.  
  501.             if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  502.                 return (HRESULT)E_FAIL;
  503.  
  504.             _RPT0(0,"Attempt tunnel load\n");
  505.  
  506.             HRESULT hr = ppf->Load(lpszFileName, mode);
  507.  
  508.             ppf->Release();
  509.  
  510.             return hr;
  511.         }
  512.  
  513.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  514.  
  515.         _RPT0(0,"Attempting to find 'PATH'...\n");
  516.         mmi.ckid = 'HTAP';
  517.         mmerr = mmioDescend(hmmio, &mmi, &mmiriff, MMIO_FINDCHUNK);
  518.         if (mmerr == MMIOERR_CHUNKNOTFOUND) throw (HRESULT)E_FAIL;
  519.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  520.  
  521.         _RPT0(0,"Allocate path memory...\n");
  522.         if (!(szPath = new char[mmi.cksize+1]))
  523.             throw (HRESULT)E_OUTOFMEMORY;
  524.  
  525.         szPath[mmi.cksize]=0;
  526.  
  527.         _RPT0(0,"Read in path...\n");
  528.  
  529.         if ((LONG)mmi.cksize != mmioRead(hmmio, szPath, mmi.cksize))
  530.             throw (HRESULT)E_FAIL;
  531.  
  532.         _RPT1(0,"File parsed, remote-path: [%s]\n", szPath);
  533.  
  534.         // now attempt to open the link
  535.  
  536.         ivdsl = GetDubServerInterface();
  537.         if (!ivdsl) throw (HRESULT)E_FAIL;
  538.  
  539.         _RPT0(0,"Have dub server interface.\n");
  540.  
  541.         ivdac = ivdsl->FrameServerConnect(szPath);
  542.         if (!ivdac) throw (HRESULT)E_FAIL;
  543.  
  544.         // retrieve streaminfo and format information
  545.  
  546.         _RPT0(0,"Connected to frameserver.\n");
  547.  
  548.         fHasAudio = ivdac->hasAudio();
  549.  
  550.         _RPT0(0,"Reading video stream info...\n");
  551.  
  552.         if (!ivdac->readStreamInfo(&vStreamInfo, FALSE, &vSampleFirst, &vSampleLast))
  553.             throw (HRESULT)E_FAIL;
  554.  
  555.         _RPT0(0,"Reading video format length...\n");
  556.  
  557.         if ((vFormatLen = ivdac->readFormat(NULL, FALSE))<=0)
  558.             throw (HRESULT)E_FAIL;
  559.  
  560.         _RPT1(0,"Allocating video format (%ld bytes)...\n", vFormatLen);
  561.  
  562.         if (!(vFormat = (BITMAPINFOHEADER *)malloc(vFormatLen)))
  563.             throw (HRESULT)E_OUTOFMEMORY;
  564.  
  565.         _RPT0(0,"Reading video format...\n");
  566.  
  567.         if (ivdac->readFormat(vFormat, FALSE)<=0)
  568.             throw (HRESULT)E_FAIL;
  569.  
  570.         if (fHasAudio) {
  571.             _RPT0(0,"Reading audio stream info...\n");
  572.  
  573.             if (!ivdac->readStreamInfo(&aStreamInfo, TRUE, &aSampleFirst, &aSampleLast))
  574.                 throw (HRESULT)E_FAIL;
  575.  
  576.             _RPT0(0,"Reading audio format length...\n");
  577.  
  578.             if ((aFormatLen = ivdac->readFormat(NULL, TRUE))<=0)
  579.                 throw (HRESULT)E_FAIL;
  580.  
  581.             _RPT1(0,"Allocating audio format (%ld bytes)...\n", aFormatLen);
  582.  
  583.             if (!(aFormat = (WAVEFORMATEX *)malloc(aFormatLen)))
  584.                 throw (HRESULT)E_OUTOFMEMORY;
  585.  
  586.             _RPT0(0,"Reading audio format...\n");
  587.  
  588.             if (ivdac->readFormat(aFormat, TRUE)<=0)
  589.                 throw (HRESULT)E_FAIL;
  590.         }
  591.  
  592.     } catch(HRESULT res) {
  593.         _RPT0(0,"*** failed!\n");
  594.  
  595.         final = res;
  596.     }
  597.  
  598.     if (hmmio) mmioClose(hmmio, 0);
  599.  
  600.     _RPT0(0,"CAVIFileRemote::Open() exit\n");
  601.  
  602.     return final;
  603. }
  604.  
  605. STDMETHODIMP CAVIFileRemote::Info(AVIFILEINFOW *psi, LONG lSize) {
  606.     AVISTREAMINFO *asi;
  607.  
  608.     _RPT0(0,"CAVIFileRemote::Info()\n");
  609.  
  610.     if (pafTunnel)
  611.         return pafTunnel->Info(psi, lSize);
  612.     
  613.     if (!psi || !ivdac) return E_FAIL;
  614.  
  615.     psi->dwMaxBytesPerSec        = 0;
  616.     psi->dwFlags                = AVIFILEINFO_HASINDEX | AVIFILEINFO_ISINTERLEAVED;
  617.     psi->dwCaps                    = AVIFILECAPS_CANREAD | AVIFILECAPS_ALLKEYFRAMES | AVIFILECAPS_NOCOMPRESSION;
  618.     psi->dwStreams                = fHasAudio ? 2 : 1;
  619.     psi->dwSuggestedBufferSize    = 0;
  620.     psi->dwWidth                = vFormat->biWidth;
  621.     psi->dwHeight                = vFormat->biHeight;
  622.     psi->dwEditCount            = 0;
  623.     wcscpy(psi->szFileType, L"VirtualDub Remote AVI");
  624.  
  625.     // determine which stream is longer.
  626.     // v_dwRate / v_dwScale < a_dwRate / a_dwScale
  627.     // v_dwRate * a_dwScale < a_dwRate * v_dwScale
  628.     //
  629.     // DON'T: Panasonic uses AVISTREAMINFO.dwLength as the frame count!
  630.  
  631.     asi = &vStreamInfo;
  632.  
  633. //    if (fHasAudio && vStreamInfo.dwRate * aStreamInfo.dwScale < aStreamInfo.dwRate * vStreamInfo.dwScale)
  634. //        asi = &aStreamInfo;
  635.  
  636.     psi->dwRate                    = asi->dwRate;
  637.     psi->dwScale                = asi->dwScale;
  638.     psi->dwLength                = asi->dwLength;
  639.  
  640.     return 0;
  641. }
  642.  
  643. STDMETHODIMP CAVIFileRemote::GetStream(PAVISTREAM *ppStream, DWORD fccType, LONG lParam) {
  644.     CAVIStreamRemote *casr;
  645.  
  646.     _RPT4(0,"%p->CAVIFileRemote::GetStream(%p, %08lx, %ld)\n", this, ppStream, fccType, lParam);
  647.  
  648.     if (pafTunnel) {
  649.         HRESULT hr;
  650.         hr = pafTunnel->GetStream(ppStream, fccType, lParam);
  651.  
  652.         _RPT2(0,"%08lx %08lx\n", *ppStream, hr);
  653.  
  654.         return hr;
  655.     }
  656.  
  657.     *ppStream = NULL;
  658.  
  659.     if (!fccType) {
  660.         if (lParam==0) fccType = streamtypeVIDEO;
  661.         else if (lParam==1) {
  662.             lParam = 0;
  663.             fccType = streamtypeAUDIO;
  664.         }
  665.     }
  666.  
  667.     if (lParam > 0) return AVIERR_NODATA;
  668.  
  669.     if (fccType == streamtypeVIDEO) {
  670.         if (!(casr = new CAVIStreamRemote(this, FALSE, &vStreamInfo, vFormat, vFormatLen, vSampleFirst, vSampleLast)))
  671.             return AVIERR_MEMORY;
  672.  
  673.         *ppStream = (IAVIStream *)casr;
  674.  
  675.     } else if (fccType == streamtypeAUDIO) {
  676.         if (!fHasAudio) return AVIERR_NODATA;
  677.  
  678.         if (!(casr = new CAVIStreamRemote(this, TRUE, &aStreamInfo, aFormat, aFormatLen, aSampleFirst, aSampleLast)))
  679.             return AVIERR_MEMORY;
  680.  
  681.         *ppStream = (IAVIStream *)casr;
  682.     } else
  683.         return AVIERR_NODATA;
  684.  
  685.     return 0;
  686. }
  687.  
  688.  
  689.  
  690.  
  691.  
  692. void CAVIFileRemote::LockPort() {
  693.     EnterCriticalSection(&csPort);
  694. }
  695.  
  696. void CAVIFileRemote::UnlockPort() {
  697.     LeaveCriticalSection(&csPort);
  698. }
  699.  
  700.  
  701.  
  702. ////////////////////////////////////////////////////////////////////////
  703. //
  704. //        CAVIStreamRemote
  705. //
  706. ////////////////////////////////////////////////////////////////////////
  707.  
  708. STDMETHODIMP CAVIStreamRemote::Create(LPARAM lParam1, LPARAM lParam2) {
  709.     _RPT1(0,"%p->CAVIStreamRemote::Create()\n", this);
  710.     return AVIERR_READONLY;
  711. }
  712.  
  713. STDMETHODIMP CAVIStreamRemote::Delete(LONG lStart, LONG lSamples) {
  714.     _RPT1(0,"%p->CAVIStreamRemote::Delete()\n", this);
  715.     return AVIERR_READONLY;
  716. }
  717.  
  718. STDMETHODIMP CAVIStreamRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  719.     _RPT1(0,"%p->CAVIStreamRemote::ReadData()\n", this);
  720.     return AVIERR_NODATA;
  721. }
  722.  
  723. STDMETHODIMP CAVIStreamRemote::SetFormat(LONG lPos, LPVOID lpFormat, LONG cbFormat) {
  724.     _RPT1(0,"%p->CAVIStreamRemote::SetFormat()\n", this);
  725.     return AVIERR_READONLY;
  726. }
  727.  
  728. STDMETHODIMP CAVIStreamRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  729.     _RPT1(0,"%p->CAVIStreamRemote::WriteData()\n", this);
  730.     return AVIERR_READONLY;
  731. }
  732.  
  733. STDMETHODIMP CAVIStreamRemote::SetInfo(AVISTREAMINFOW *psi, LONG lSize) {
  734.     return AVIERR_READONLY;
  735. }
  736.  
  737.  
  738.  
  739. CAVIStreamRemote::CAVIStreamRemote(const CLSID& rclsid, void **pUnknown) : iclassfactory(this) {
  740.     _RPT1(0,"%p->CAVIStreamRemote()\n", this);
  741.     m_refs = 0; AddRef();
  742.  
  743.     parent            = NULL;
  744.     streamInfo        = NULL;
  745.     wfexFormat        = NULL;
  746.     bmihFormat        = NULL;
  747. }
  748.  
  749. CAVIStreamRemote::CAVIStreamRemote(CAVIFileRemote *parentPtr, BOOL isAudio, AVISTREAMINFO *asi, void *format, long format_len, long sample_first, long sample_last) : iclassfactory(this) {
  750.     _RPT2(0,"%p->CAVIStreamRemote(%s)\n", this, isAudio ? "audio" : "video");
  751.     m_refs = 0; AddRef();
  752.  
  753.     parentPtr->AddRef();
  754.  
  755.     parent            = parentPtr;
  756.     fAudio            = isAudio;
  757.     streamInfo        = asi;
  758.     wfexFormat        = (WAVEFORMATEX *)format;
  759.     bmihFormat        = (BITMAPINFOHEADER *)format;
  760.     lFormatLen        = format_len;
  761.     lSampleFirst    = sample_first;
  762.     lSampleLast        = sample_last;
  763. }
  764.  
  765. CAVIStreamRemote::~CAVIStreamRemote() {
  766.     _RPT1(0,"%p->~CAVIStreamRemote()\n", this);
  767.  
  768.     parent->Release();
  769. }
  770.  
  771. STDMETHODIMP_(LONG) CAVIStreamRemote::Info(AVISTREAMINFOW *psi, LONG lSize) {
  772.     AVISTREAMINFOW asiw;
  773.  
  774.     _RPT3(0,"%p->CAVIStreamRemote::Info(%p, %ld)\n", this, psi, lSize);
  775.  
  776.     _RPT1(0,"stream length: %ld\n", streamInfo->dwLength);
  777.     memset(psi, 0, lSize);
  778.     memcpy(&asiw, streamInfo, sizeof(AVISTREAMINFO));
  779.     wcscpy(asiw.szName, fAudio ? L"VDub remote audio #1" : L"VDub remote video #1");
  780.     if (lSize < sizeof(AVISTREAMINFOW)) {
  781.         memcpy(psi, &asiw, lSize);
  782.     } else {
  783.         memcpy(psi, &asiw, sizeof(AVISTREAMINFOW));
  784.     }
  785.  
  786.     return 0;
  787. }
  788.  
  789. STDMETHODIMP_(LONG) CAVIStreamRemote::FindSample(LONG lPos, LONG lFlags) {
  790.     _RPT3(0,"%p->CAVIStreamRemote::FindSample(%ld, %08lx)\n", this, lPos, lFlags);
  791.  
  792.     if (lFlags & FIND_FORMAT)
  793.         return -1;
  794.  
  795.     if (lFlags & FIND_FROM_START)
  796.         return 0;
  797.  
  798.     return lPos;
  799. }
  800.  
  801. STDMETHODIMP CAVIStreamRemote::Read(LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples) {
  802.     HRESULT hres = 0;
  803.     int err;
  804.  
  805.     _RPT3(0,"%p->CAVIStreamRemote::Read(%ld samples at %ld)\n", this, lSamples, lStart);
  806.     _RPT2(0,"\tbuffer: %ld bytes at %p\n", cbBuffer, lpBuffer);
  807.  
  808.     parent->LockPort();
  809.  
  810.     if (plSamples) *plSamples = 0;
  811.     if (plBytes) *plBytes = 0;
  812.  
  813.     // Panasonic does some bad things if you give it fewer samples than it asks for,
  814.     // particularly if cbBuffer is 0 and lpBuffer = NULL.
  815.  
  816.     if (fAudio) {
  817.         LONG lABytes, lASamples;
  818.  
  819.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  820.             lSamples = cbBuffer;
  821.  
  822.             while(lSamples > 0) {
  823.                 err = parent->ivdac->readAudio(lStart, lSamples, lpBuffer, cbBuffer, &lABytes, &lASamples);
  824.  
  825.                 if (err == VDSRVERR_TOOBIG || !lASamples)
  826.                     break;
  827.  
  828.                 if (err != VDSRVERR_OK) {
  829.                     hres = AVIERR_FILEREAD;
  830.                     break;
  831.                 }
  832.  
  833.                 if (plBytes)
  834.                     *plBytes += lABytes;
  835.  
  836.                 if (plSamples)
  837.                     *plSamples += lASamples;
  838.  
  839.                 if (lpBuffer)
  840.                     lpBuffer = (char *)lpBuffer + lABytes;
  841.  
  842.                 cbBuffer -= lABytes;
  843.                 lStart += lASamples;
  844.                 lSamples -= lASamples;
  845.             }
  846.     } else {
  847.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  848.             lSamples = 1;
  849.  
  850.         if (!lpBuffer) {
  851.             if (plSamples) *plSamples = 1;
  852.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  853.         } else if (cbBuffer < (long)bmihFormat->biSizeImage) {
  854.             _RPT1(0,"\tBuffer too small; should be %ld samples\n", bmihFormat->biSizeImage);
  855.             hres = AVIERR_BUFFERTOOSMALL;
  856.             if (plSamples) *plSamples = 1;
  857.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  858.         } else {
  859.             _RPT0(0,"\tAttempting to read\n");
  860.             err = parent->ivdac->readVideo(lStart, lpBuffer);
  861.             if (!err) {
  862.                 _RPT0(0,"\tRead successful\n");
  863.                 if (plSamples) *plSamples = 1;
  864.                 if (plBytes) *plBytes = bmihFormat->biSizeImage;
  865.             } else {
  866.                 _RPT0(0,"\tError!\n");
  867.                 hres = AVIERR_FILEREAD;
  868.             }
  869.         }
  870.     }
  871.  
  872.     parent->UnlockPort();
  873.  
  874.     return hres;
  875. }
  876.  
  877. STDMETHODIMP CAVIStreamRemote::ReadFormat(LONG lPos, LPVOID lpFormat, LONG *lpcbFormat) {
  878.     _RPT1(0,"%p->CAVIStreamRemote::ReadFormat()\n", this);
  879.  
  880.     if (!lpFormat) {
  881.         *lpcbFormat = lFormatLen;
  882.         return S_OK;
  883.     }
  884.  
  885.     if (*lpcbFormat < lFormatLen)
  886.         memcpy(lpFormat, wfexFormat, *lpcbFormat);
  887.     else {
  888.         memcpy(lpFormat, wfexFormat, lFormatLen);
  889.         *lpcbFormat = lFormatLen;
  890.     }
  891.  
  892.     return S_OK;
  893. }
  894.  
  895. STDMETHODIMP CAVIStreamRemote::Write(LONG lStart, LONG lSamples, LPVOID lpBuffer,
  896.     LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, 
  897.     LONG FAR *plBytesWritten) {
  898.  
  899.     _RPT1(0,"%p->CAVIStreamRemote::Write()\n", this);
  900.  
  901.     return AVIERR_READONLY;
  902. }
  903.  
  904.